package player

import (
	"GameServer/Common/utils"
	"GameServer/Game/activity"
	"GameServer/Game/activity_rank"
	"GameServer/Game/christmas"
	"GameServer/Game/dbmodule"
	"GameServer/Game/energy_quick"
	"GameServer/Game/entrust_activ"
	"GameServer/Game/entrust_rank"
	"GameServer/Game/errors"
	"GameServer/Game/jackpot"
	"GameServer/Game/lib"
	"GameServer/Game/m"
	"GameServer/Game/mulcombat"
	"GameServer/Game/sp"
	"GameServer/Game/timer"
	"GameServer/Game/union"
	"GameServer/globalFunc"
	"strconv"
	"sync"
	"time"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"
)

type Players struct {
	muser map[string]*Player //在线玩家
	//mName     map[string]string//Key UserName Value Uid
	mOfflines map[string]*m.User //离线玩家
	wg        *sync.WaitGroup
	rw        *sync.RWMutex
}

func init() {
	PlayersModule = &Players{
		muser: make(map[string]*Player, 0),
		//mName:     make(map[string]string, 0),
		rw:        new(sync.RWMutex),
		wg:        new(sync.WaitGroup),
		mOfflines: make(map[string]*m.User, 0),
	}
}

func (ps *Players) Init() {
	//  @todo 有性能为题
	offlines := make([]*m.User, 0)
	err := dbmodule.MgoDB.GameDB.FindAll("user", nil, nil, &offlines)
	if err != nil {
		panic(err)
	}

	// 启动游戏，统计玩家个数。
	PlayerCount = int64(len(offlines))

	for _, item := range offlines {
		ps.mOfflines[item.Uid.Hex()] = item
		if item.OfflineTime == 0 {
			item.OffLine()
		}
		//ps.mName[item.Name] = item.Uid.Hex()
	}
	// 注册函数指针
	globalFunc.Register_ChangeUserSlotActRankGroup(ChangeUserSlotActRankGroup)
	globalFunc.Register_BroadCastList(BroadCastList)
	globalFunc.Register_BroadData(BroadData)
	globalFunc.Register_SendMailToUid(SendMailToUid)
	globalFunc.Register_GetUserByUID(GetUser)

	// 定时器
	// timer.AddFunc("@every 20m", func() {
	// 	fmt.Println("20 分钟调用一次")
	// 	ps.twentyTimer()
	// })

	texp := "TZ=UTC 0 0 0 * * *"
	timer.AddFunc(texp, func() {
		log.WithFields(log.Fields{
			"data": "",
		}).Info("凌晨执行一次")
		union.UnionModule.CleanUser(GetUser, BroadData)
		//activity.ActivityModule.ReCheckActActivityList(ps.GetOnlinePlayersUIDArr(), BroadCastList)
		activity_rank.ActivityRankModule.ZeroTimeFunction(SendMailToUid)
		mulcombat.Module.DispatchRankReward(SendMailToUid)
		mulcombat.Module.CheckActiv()
		entrust_activ.Module.CheckActiv()
		entrust_rank.Module.DispatchRankReward(SendMailToUid)
		entrust_rank.Module.CheckActiv()
		jackpot.Module.CheckActiv()
		energy_quick.Module.CheckRestoreEnergy()
		christmas.Module.CheckActiv()
	})
	texp2 := "0 0 */1 * * *"
	timer.AddFunc(texp2, func() {
		log.WithFields(log.Fields{
			"data": "吉星需要的",
		}).Info("活动启动，改为每小时检测一次")
		activity.ActivityModule.ReCheckActActivityList(ps.GetOnlinePlayersUIDArr(), BroadCastList)
	})
}

func (ps *Players) Run(closeSig chan bool) {

}

func (ps *Players) get(uid string) (r *Player, ok bool) {

	if uid == "" {
		return nil, false
	}

	ps.rw.Lock()
	defer ps.rw.Unlock()
	// 玩家在线
	if r, ok = ps.muser[uid]; ok {
		return r, ok
	}
	r = NewPlayer()
	// 玩家离线
	if user, ok := ps.mOfflines[uid]; ok {
		r.User = user
		return r, ok
	}
	// 玩家不在线，也不离线，从缓存中获取。缓存中没有，会从数据库中获取。
	v, ok := m.Cache.Get("user", uid)
	if !ok {
		return
	}
	user := v.(*m.User)
	ps.mOfflines[user.Uid.Hex()] = user

	r.User = user
	return
}

// func (ps *Players) getByName(name string) (r *Player, ok bool) {
// 	if name == "" {
// 		return
// 	}
// 	if v, ok := ps.mName[name]; ok {
// 		return ps.get(v)
// 	}
// 	return
// }

func (ps *Players) GetUser(uid string) (r *m.User, ok bool) {
	if uid == "" {
		return
	}
	p, ok := ps.get(uid)
	if !ok {
		return
	}
	r = p.User
	return
}

func (ps *Players) GetPlayer(uid string) (r *Player, ok bool) {
	return ps.get(uid)
}

// 通过用户uid，获取玩家玩家信息
func (ps *Players) GetPByUid(uid string) (r *Player, err error) {
	ps.rw.Lock()
	defer ps.rw.Unlock()

	if val, ok := ps.muser[uid]; ok {
		return val, nil
	}
	return nil, errors.New("没有该UID的玩家登录")
}

// 通过用户uid，获取用户信息
func (ps *Players) GetUByUid(uid string) (r *m.User, err error) {
	ps.rw.RLock()
	defer ps.rw.RUnlock()

	if val, ok := ps.muser[uid]; ok {
		return val.User, nil
	}
	if val, ok := ps.mOfflines[uid]; ok {
		return val, nil
	}
	return nil, errors.New("没有该UID的用户")
}

// func (ps *Players) GetPlayerByName(name string) (r *Player, ok bool) {
// 	return ps.getByName(name)
// }

//获取在线玩家
func (ps *Players) GetOnlinePlayers() (r []*Player) {
	for _, item := range ps.muser {
		r = append(r, item)
	}
	return
}

//获取在线玩家人数
func (ps *Players) GetOnlineNum() (num int) {
	return len(ps.muser)
}

// 获取所有离线玩家数据
func (ps *Players) Offlines() (rs []*m.User) {
	for _, item := range ps.mOfflines {
		rs = append(rs, item)
	}
	return
}

//获取在玩玩家UID
func (ps *Players) GetOnlinePlayersUIDArr() (r []string) {
	for key, item := range ps.muser {
		// 过滤掉新手玩家
		if item.User.MaxPos.LockBlockTid < 2 {
			continue
		}
		r = append(r, key)
	}
	return
}

//获取所有玩家
func (ps *Players) GetAllPlayers() (r []*m.User) {
	//获取在线玩家
	for _, item := range ps.muser {
		r = append(r, item.User)
	}
	//获取离线玩家
	for _, item := range ps.mOfflines {
		r = append(r, item)
	}
	return
}

//玩家上线
func (ps *Players) Online(p *Player) {
	ps.rw.Lock()
	uid := p.User.Uid.Hex()
	ps.muser[uid] = p
	p.User.OnLine()

	delete(ps.mOfflines, uid)
	ps.rw.Unlock()
}

// 玩家离线
func (ps *Players) Offline(u *m.User) {
	ps.rw.Lock()
	ps.mOfflines[u.Uid.Hex()] = u
	u.OffLine()
	delete(ps.muser, u.Uid.Hex())
	ps.rw.Unlock()
	union.UnionModule.OffLine(u.UnionId, u.Uid.Hex(), BroadData)
}

// 玩家封禁
func (ps *Players) ClosureETime(uid string, closureEndTime int64) (err error) {
	var msg string = "玩家被封禁。"
	// 封禁结束时间<当前时间，都是解封
	if closureEndTime < utils.TNow().Unix() {
		msg = "玩家已被解封。"
	}
	if val, ok := ps.muser[uid]; ok {
		val.User.ClosureETime(closureEndTime)
		log.WithFields(log.Fields{
			"uid":    val.User.Uid.Hex(),
			"method": "ClosureETime",
		}).Debug(msg)
		val.Send(&sp.ClosureLoginRequest{})
		val.closureLogin = true
		PlayersModule.Offline(val.User)
		// 移除老虎机占用对象
		val.RemoveSlotUser()
		go func() {
			time.Sleep(time.Second)
			if val.client != nil {
				val.client.Close()
			}
		}()
		return nil
	}
	if val, ok := ps.mOfflines[uid]; ok {
		log.WithFields(log.Fields{
			"uid":    val.Uid.Hex(),
			"method": "ClosureETime",
		}).Debug(msg)
		val.ClosureETime(closureEndTime)
		return nil
	}
	return errors.New("没有该玩家")
}

// 设置超级账号
func (ps *Players) SetWhite(uid string, superAccount int64) (err error) {
	if val, ok := ps.muser[uid]; ok {
		val.User.ModifySuperAccount(superAccount)
		return nil
	}
	if val, ok := ps.mOfflines[uid]; ok {
		val.ModifySuperAccount(superAccount)
		return nil
	}
	return errors.New("没有该玩家")
}

func (ps *Players) twentyTimer() {
	for _, p := range ps.muser {
		if p == nil || p.User == nil {
			continue
		}
		go func(p1 *Player) {
			p1.RefreshSlotUser()
		}(p)
	}
}

func (ps *Players) Destroy() {
}

var (
	PlayersModule *Players
	PlayerCount   int64 // 统计玩家数量
)

func GetOnlinePlayers() (r []*Player) {
	return PlayersModule.GetOnlinePlayers()
}

func GetUser(uid string) (r *m.User, ok bool) {
	return PlayersModule.GetUser(uid)
}

func GetPlayerByUid(uid string) (r *Player, ok bool) {
	return PlayersModule.GetPlayer(uid)
}

// 获取玩家信息
func GetPByUid(uid string) (r *Player, err error) {
	return PlayersModule.GetPByUid(uid)
}

// 获取用户信息
func GetUByUid(uid string) (r *m.User, err error) {
	return PlayersModule.GetUByUid(uid)
}

//通过页码和每页数量，获取用户信息
func GetUserList(page, pageNum int) (list []*m.User, num int) {
	onLineNum, _ := lib.CountOnline()
	num, _ = lib.CountUser()
	list = make([]*m.User, 0)
	list1, err := lib.FindOnLinePage(page, pageNum)
	if err != nil {
		return
	}
	for _, item := range list1 {
		itemT, err := PlayersModule.GetUByUid(item.Uid.Hex())
		if err != nil {
			continue
		}
		list = append(list, itemT)
	}
	length := len(list1)
	start := 0
	if length >= pageNum {
		return
	} else if length == 0 {
		start = page*pageNum - onLineNum
	} else { // 0 < lenght < pageNum
		pageNum -= length
	}

	list2, err := lib.FindOffLinePage(start, pageNum)
	if err != nil {
		return
	}
	list = append(list, list2...)
	return
}

// 通过用户accountId查询用户信息
func GetUserListByAccountId(accountId string) (list []*m.User, num int) {
	list = make([]*m.User, 0)
	uid, err := lib.FindUidByAccountId(accountId)
	if err != nil {
		return
	}
	u, err := PlayersModule.GetUByUid(uid)
	if err != nil {
		return
	}
	list = append(list, u)
	num = 1
	return
}

// 通过用户的identifId查询用户信息
func GetUserListByIdentifId(identifId string) (list []*m.User, num int) {
	list = make([]*m.User, 0)
	uid, err := lib.FindUidByIdentifId(identifId)
	if err != nil {
		return
	}
	u, err := PlayersModule.GetUByUid(uid)
	if err != nil {
		return
	}
	list = append(list, u)
	num = 1
	return
}

// 通过用户的uid查询用户信息
func GetUserListByUid(uid string) (list []*m.User, num int) {
	list = make([]*m.User, 0)
	u, err := PlayersModule.GetUByUid(uid)
	if err != nil {
		return
	}
	list = append(list, u)
	num = 1
	return
}

// 通过用户的name查询用户信息
func GetUserListByName(name string) (list []*m.User, num int) {
	list, err := lib.FindUserListByName(name)
	num = len(list)
	if err != nil {
		return
	}
	return
}

// 查询超级用户
func GetUserListBySuperAccount(superAccount string) (list []*m.User, num int) {
	list = make([]*m.User, 0)
	superAccountT, _ := strconv.ParseInt(superAccount, 10, 64)
	list, err := lib.FindUserListBySuperAccount(superAccountT)
	num = len(list)
	if err != nil {
		return
	}
	return
}

// 通过用户uid，查询用户宠物
func GetUserPetInfoByUid(uid string) (r interface{}, ok bool) {
	r, ok = m.Cache.Get("userPet", uid)
	return
}

func GetHerosInfoByUid(uid string) (r interface{}, ok bool) {
	u := &m.User{
		Uid: bson.ObjectIdHex(uid),
	}
	ok = true
	r = lib.HeroList(u)
	return
}

//获取在线玩家数量
func GetOnlineNum() (num int) {
	return PlayersModule.GetOnlineNum()
}

//修改玩家属性
func SetUserPetInfo(userPet *m.UserPet) (ok bool) {
	uProp := m.NewUpdateProp()
	p, ok := GetPlayerByUid(userPet.Uid.Hex())
	if !ok {
		return
	}
	var val int64 = userPet.FoodNum - p.User.GetUserPet().FoodNum
	if userPet.FoodNum >= 0 && val != 0 { //修改宠物饲料
		uProp.Petinfo = p.User.GetUserPet().AddFoodNum(val)
	}
	val = userPet.ExpNum - p.User.GetUserPet().ExpNum
	if userPet.ExpNum >= 0 && val != 0 { //修改宠物经验药水
		uProp.Petinfo = p.User.GetUserPet().AddExpNum(val)
	}
	if p.User.IsOnLine() {
		p.TimelyUpdateProp(0, uProp)
		utils.AsyncFunc(func() {
			p.UpdateProp(0, uProp)
		})
	}
	return
}

// 封禁玩家，封禁玩家uid，封禁时间长closureLength秒
func SetClosureTime(uid string, closureLength int64) (err error) {
	closureEndTime := utils.TNow().Unix() + closureLength
	return PlayersModule.ClosureETime(uid, closureEndTime)
}

// 封禁玩家，封禁玩家uid，封禁结束时间closureEndTime
func SetClosureETime(uid string, closureEndTime int64) (err error) {
	return PlayersModule.ClosureETime(uid, closureEndTime)
}

// 设置玩家白名单
func SetWhite(uid string, superAccount int64) (err error) {
	return PlayersModule.SetWhite(uid, superAccount)
}
